
/**
 * 均匀随机选择一个
 * @param list 
 * @returns 待选列表
 */
export function randomChoose<T>(list: T[]): T {
    if (list == null) return null;
    if (list.length == 0) return null;
    return list[Math.floor(Math.random() * list.length)];
}
// test
// RCT.randomChoose([1,2,3,4,5])

/**
 * 均匀随机选择，多个
 * @param _list 待选列表
 * @param count 数量
 * @returns 
 */
export function randomChooseMulti<T>(_list: T[], count: number = 1): T[] {
    if (_list == null) return [];
    let list = new Array(..._list);
    let result: T[] = [];
    while (result.length < count) {
        let idx = Math.floor(Math.random() * list.length);
        result.push(...list.splice(idx, 1));
        if (list.length <= 0) break;
    }
    return result;
}
// test
// RCT.randomChooseMulti([1,2,3,4,5], 4)

let sumKey = (k: string) => `${k}_sum`; // 概率随机用的

/**
 * 为概率数组加入概率和
 * @param list 待选列表
 * @param probKey 选择概率数值Key
 */
export function genListProbSum<T>(list: T[], probKey: string) {
    let sum = 0;
    for (let i = 0; i < list.length; i++) {
        let item = list[i];
        sum += item[probKey];
        item[sumKey(probKey)] = sum;
    }
}
/**
 * 从列表中概率随机选择，选择一个
 * @param list 待选列表
 * @param probKey 选择概率数值Key
 * @param forceCache 强制重新计算概率和
 */
export function randomChooseWithProb<T>(list: T[], probKey: string, forceCache: boolean = false): T {
    if (list == null || list.length == 0) return null;
    if (forceCache) genListProbSum(list, probKey);
    // 策略，只当数据中已经含有probsum进行处理，遍历中一旦发现并没有，就重新调用该函数的forceCache版本
    let max = list[list.length - 1][sumKey(probKey)];
    if (max == null) return randomChooseWithProb(list, probKey, true);
    let randomValue = Math.random() * max;
    for (let i = 0; i < list.length; i++) {
        let item = list[i];
        let probSum = item[sumKey(probKey)];
        if (max == null) return randomChooseWithProb(list, probKey, true);
        if (randomValue < probSum) return item;
    }
}
// test
// RCT.randomChooseWithProb([{p:10}, {p:100}, {p:20}], 'p').map(_ => _.p)

/**
 * 从列表中概率随机选择，选择多个
 * @param _list 待选列表
 * @param probKey 选择概率数值
 * @param count 
 * @returns 
 */
export function randomChooseWithProbMulti<T>(_list: T[], probKey: string, count: number): T[] {
    if (_list == null || _list.length == 0) return [];
    let list = new Array(..._list);
    let result: T[] = [];
    while (result.length < count) {
        genListProbSum(list, probKey);
        let max = list[list.length - 1][sumKey(probKey)];
        let randomValue = Math.random() * max;
        for (let i = 0; i < list.length; i++) {
            let item = list[i];
            let probSum = item[sumKey(probKey)];
            if (randomValue < probSum) {
                result.push(item);
                list.splice(i, 1);
                break;
            }
        }
        if (list.length <= 0) break;
    }
    return result;
}
// test
// RCT.randomChooseWithProbMulti([{ p: 10 }, { p: 100 }, { p: 20 }], 'p', 10).map(_ => _.p);



// (<any>window).RCT = { randomChoose, randomChooseMulti, randomChooseWithProb, randomChooseWithProbMulti };